package services

import (
	"encoding/json"
	"fmt"
	"go.uber.org/zap"
	"io/ioutil"
	"net/http"
	"net/url"
	"purchase-mall/dao/redis"
	"purchase-mall/models"
	"purchase-mall/utils"
	"strconv"
	"sync"
	"time"
)

var queryMap = map[string]string{
	"cdn":      "sum(count_over_time({job=\"cdn-logs/cdn-reporter\"}[24h]))",
	"gateway":  "sum(count_over_time({filename=\"/apisix/log/error.log\", from=\"access log\",env=\"prod\",exporter=\"promtail\"} [24h]))",
	"upstream": "sum(count_over_time({from=\"tstiles log\"} [24h]))",
}

// GetAccessTotalService 获取访问总量
func GetAccessTotalService(endTimes map[string]int64) (data []*models.AccessTotalInfo, err error) {
	var dataMap = make(map[string]*models.AccessTotalInfo, 0)
	for timeD, _ := range endTimes {
		dataMap[timeD] = new(models.AccessTotalInfo)
	}

	var wg sync.WaitGroup
	wg.Add(len(queryMap))
	for k, _ := range queryMap {
		go func(k string) {
			defer wg.Done()

			for timeD, endTime := range endTimes {
				dataMap[timeD].Time = timeD

				err, resp := RequestAccessTotal(k, endTime)
				if err == nil {
					var requestNum int
					if resp.Data.Result != nil && len(resp.Data.Result) > 0 {
						if resp.Data.Result[0].Value != nil && len(resp.Data.Result[0].Value) >= 2 {
							requestNum, _ = strconv.Atoi(resp.Data.Result[0].Value[1].(string))
						}
					}
					switch k {
					case "cdn":
						dataMap[timeD].CdnTotalNum = int64(requestNum)
					case "gateway":
						dataMap[timeD].GatewayTotalNum = int64(requestNum)
					case "upstream":
						dataMap[timeD].UpstreamTotalNum = int64(requestNum)
					}
				}
			}
		}(k)
	}
	wg.Wait()

	data = make([]*models.AccessTotalInfo, 0, len(endTimes))
	for _, v := range dataMap {
		data = append(data, v)
	}

	BubbleAccessTotal(data)

	//存redis
	go SetRedisAccessTotal(data)

	return
}

func RequestAccessTotal(k string, endTime int64) (err error, res RespJson) {
	params := url.Values{}
	parseURL, err := url.Parse(utils.RequestGetUrlNoParams)
	if err != nil {
		return
	}
	params.Set("query", queryMap[k])
	params.Set("time", strconv.FormatInt(endTime, 10))
	parseURL.RawQuery = params.Encode()
	urlPathWithParams := parseURL.String()

	client := http.Client{
		Timeout: 10 * time.Minute,
	}

	resp, err := client.Get(urlPathWithParams)
	if err != nil {
		zap.L().Error("Loki Http Api GetAccessTotalService failed",
			zap.Int64("time", endTime),
			zap.Error(err))
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)

	//if string(body) == "too many outstanding requests" {
	//	return RequestAccessTotal(k, endTime)
	//}

	if err != nil {
		return
	}
	err = json.Unmarshal(body, &res)
	if err != nil {
		return
	}

	if res.Status != "success" {
		return
	}

	return
}

func SetRedisAccessTotal(data []*models.AccessTotalInfo) {
	if data != nil && len(data) > 0 {
		for _, d := range data {
			if d.CdnTotalNum > 0 && d.GatewayTotalNum > 0 && d.UpstreamTotalNum > 0 {
				redis.SetAccessTotal(fmt.Sprintf("%s|%s", d.Time, "cdn_access_total"), d.CdnTotalNum)
				redis.SetAccessTotal(fmt.Sprintf("%s|%s", d.Time, "gateway_access_total"), d.GatewayTotalNum)
				redis.SetAccessTotal(fmt.Sprintf("%s|%s", d.Time, "upstream_access_total"), d.UpstreamTotalNum)
			}
		}
	}
}
